﻿Imports System.Xml
Imports System.IO
Imports System.Windows.Forms
Imports System.Data
Imports System.Collections
Imports System.Text.RegularExpressions
Imports Microsoft.Office.Interop.Word
Imports Chiroredactie2007.My.Resources

Module Eindredactie

    Private Const BESTANDSNAAM_VERVANGINGEN As String = "VerbeteringsInstellingen.xml"
    Private Const BESTANDSNAAM_NIEUWE_VERVANGINGEN As String = "NieuweVerbeteringsInstellingen.xml"

    Private ReadOnly xdoc As New XmlDocument

    Private vervangForm As VervangMetOptiesVenster
    Private verv As Vervanging
    Private selectie As Selection
    Private doc As Document
    Private comments As String = String.Empty

#Region " public methods "

    ''' <summary>
    ''' Het hele geautomatiseerde eindredactieproces doorlopen
    ''' </summary>
    Public Sub Uitvoeren()
        Dim msg As String

        WeergaveRegelen()
        doc = Globals.ThisAddIn.Application.ActiveDocument

        doc.TrackRevisions = False

        HyperlinksVerwijderen()

        ' Gekrulde aanhalingstekens vervangen door rechte, zodat vervangingen uit het xml-bestand ook lukken
        ' met een aanhalingsteken. Chiro's moet Chirogroepen worden, maar met een gekrulde apostrof vinden we
        ' dat niet.
        verv = New Vervanging()
        verv.Vervangen("‘", "'")
        verv.Vervangen("’", "'")

        ' TODO:
        ' If MessageBox.Show("Wijzigingen bijhouden?", VraagString, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) = DialogResult.Yes Then
        '    doc.TrackRevisions = True
        ' End If

        ' Ga na of er al "Taalcorrectie afgerond" in de comments staat. Is dat het geval, vraag dan wat er moet gebeuren.
        ' Is dat nog niet het geval, ga dan gewoon verder.
        If doc.BuiltInDocumentProperties(WdBuiltInProperty.wdPropertyComments).Value IsNot Nothing Then
            comments = doc.BuiltInDocumentProperties(WdBuiltInProperty.wdPropertyComments).Value.ToString

            If InStr(comments, TaalcorrectieAfgewerktString) > 0 OrElse InStr(comments, TaalcorrectieVoorlopigAfgerondString) > 0 Then
                msg = String.Format(TaalcorrectieResettenString, Environment.NewLine, _
                      doc.BuiltInDocumentProperties(WdBuiltInProperty.wdPropertyComments).Value.ToString)

                If MessageBox.Show(msg, VraagString, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) = DialogResult.No Then
                    ' Taalcorrectie wordt erkend
                    Exit Sub
                Else
                    ' De vermelding over de taalcorrectie komt waarschijnlijk van een bestand dat als
                    ' basis of sjabloon gebruikt werd, of het is al nagelezen maar alleen 'voorlopig afgerond'.
                    ' We vervangen de vermelding door een andere.
                    CommentSchrijven(EindredactieBegonnenString)
                End If
            ElseIf InStr(comments, AutomatischeEindredactieUitgevoerdString) > 0 OrElse InStr(comments, EindredactieAfgerondString) > 0 Then
                msg = String.Format(EindredactieResettenString, Environment.NewLine, _
                      doc.BuiltInDocumentProperties(WdBuiltInProperty.wdPropertyComments).Value.ToString)

                If MessageBox.Show(msg, VraagString, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) = DialogResult.No Then
                    ' Eindredactie wordt erkend
                    Exit Sub
                Else
                    ' De vermelding over de taalcorrectie komt waarschijnlijk van een bestand dat als
                    ' basis of sjabloon gebruikt werd. We vervangen ze door een andere vermelding.
                    CommentSchrijven(EindredactieBegonnenString)
                End If
            ElseIf InStr(comments, TaalcorrectieVoorlopigAfgerondString) > 0 Then
                ' TODO!!
            Else
                ' Er staat nog niets in de comments over afgeronde taalcorrectie of afgeronde eindredactie,
                ' maar er staat misschien wel iets anders. We voegen de nieuwe vermelding toe aan wat er al stond.
                CommentToevoegen(EindredactieBegonnenString)
            End If
        Else
            ' Die comments zijn leeg
            CommentToevoegen(EindredactieBegonnenString)
        End If

        ' Doorloop de verschillende opdrachten, al dan niet aangepast door gebruikersinstellingen
        Dim vlag As Boolean = False

        Try
            verv = New Vervanging()
            verv.UurnotatieVervangen()
            CommentToevoegen(UurnotatieGeluktString)
        Catch ex As Exception
            CommentToevoegen(UurnotatieMisluktString)
            vlag = True
        End Try

        Try
            verv = New Vervanging()
            verv.Bedragnotatievervangen()
            CommentToevoegen(BedragnotatieGeluktString)
        Catch ex As Exception
            CommentToevoegen(BedragnotatieMisluktString)
            vlag = True
        End Try

        Try
            verv = New Vervanging()
            verv.TelefoonnummernotatieVervangen()
            CommentToevoegen(TelNrNotatieGeluktString)
        Catch ex As Exception
            CommentToevoegen(TelNrNotatieMisluktString)
            vlag = True
        End Try

        Try
            verv = New Vervanging()
            verv.SuperscriptInRangtelwoordenVervangen()
            CommentToevoegen(SuperscriptInRangtelwoordenGeluktString)
        Catch ex As Exception
            CommentToevoegen(SuperscriptInRangtelwoordenMisluktString)
            vlag = True
        End Try

        Try
            If InStr(comments, VervangingenGeluktString) > 0 AndAlso MessageBox.Show(VervangingenOpnieuwString, VraagString, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) = DialogResult.No Then
                Exit Try
            Else
                AutomatischVervangen()
                CommentToevoegen(VervangingenGeluktString)
            End If
        Catch ex As Exception
            CommentToevoegen("Automatische vervangingen mislukt")
            vlag = True
        End Try

        Try
            VervangingsfeedbackToevoegen()
        Catch ex As Exception
            CommentToevoegen("Vervangingsfeedback toevoegen mislukt")
            vlag = True
        End Try

        If vlag = True Then
            MessageBox.Show(EindredactieFoutenString, InfoString, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1)
        Else
            CommentToevoegen(AutomatischeEindredactieUitgevoerdString)
        End If

        ' Toon de nieuwe comments, ter controle
        MessageBox.Show(doc.BuiltInDocumentProperties(WdBuiltInProperty.wdPropertyComments).Value.ToString, InfoString, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1)

        doc.TrackRevisions = False

        ' Ga naar het begin van het document. We gebruiken niet meer 'selectie' maar wel de fully qualified toestand
        ' omdat we anders mogelijk de foutmelding krijgen dat het object (de selectie) al verwijderd is.
        Globals.ThisAddIn.Application.Selection.HomeKey(Unit:=WdUnits.wdStory)
    End Sub

    ''' <summary>
    ''' Verandert alle hyperlinks in platte tekst
    ''' </summary>
    Public Sub HyperlinksVerwijderen()
        Dim aantal As Integer

        doc = Globals.ThisAddIn.Application.ActiveDocument
        selectie = Globals.ThisAddIn.Application.Selection
        aantal = doc.Hyperlinks.Count

        For i = aantal To 1 Step -1
            doc.Hyperlinks(i).Range.Fields(1).Result.Select()

            ' Controleren of de url wel weergegeven wordt in de tekst. Anders houden we alleen nietszeggende tekst over,
            ' zonder het juist adres erbij.

            If InStr(doc.Hyperlinks(i).TextToDisplay, "http://") <= 0 Then
                doc.Hyperlinks(i).Address = Right(doc.Hyperlinks(i).Address, Len(doc.Hyperlinks(i).Address) - 7)
            End If

            '' OPM: het volgende werkt blijkbaar niet, dus hebben we verderop een extra controle
            'If Right(doc.Hyperlinks(i).Address, 1) = "/" Then
            '    doc.Hyperlinks(i).Address = Left(doc.Hyperlinks(i).Address, Len(doc.Hyperlinks(i).Address) - 1)
            'End If

            If Right(doc.Hyperlinks(i).TextToDisplay, 1) = "/" Then
                doc.Hyperlinks(i).TextToDisplay = Left(doc.Hyperlinks(i).TextToDisplay, Len(doc.Hyperlinks(i).TextToDisplay) - 1)
            End If

            If Left(doc.Hyperlinks(i).Address, 7) <> "mailto:" AndAlso doc.Hyperlinks(i).Address <> doc.Hyperlinks(i).TextToDisplay Then
                ' De extra controle waarvan sprake hierboven
                If doc.Hyperlinks(i).Address <> doc.Hyperlinks(i).TextToDisplay & "/" Then
                    doc.Hyperlinks(i).TextToDisplay = String.Format("{0} ({1})", doc.Hyperlinks(i).TextToDisplay, doc.Hyperlinks(i).Address)
                End If
            End If

            ' Opmaak en hyperlink verwijderen
            selectie.ClearFormatting()
            doc.Hyperlinks(i).Delete()
        Next

        Globals.ThisAddIn.Application.Selection.HomeKey(Unit:=WdUnits.wdStory)
    End Sub

    ''' <summary>
    ''' Verwijdert overbodige spaties en zet spaties waar ze soms vergeten worden.
    ''' </summary>
    Public Sub SpatiëringUitvoeren()
        verv = New Vervanging
        verv.Vervangen("  ", " ")
        verv.Vervangen(" .", ".")
        verv.Vervangen(" ,", ",")
        verv.Vervangen("...", " ...")
        verv.Vervangen("  ...", " ...")
        verv.Vervangen(" :", ":")
        verv.Vervangen(" !", "!")
        verv.Vervangen(" ?", "?")
        verv.Vervangen("( ", "(")
        verv.Vervangen(" )", ")")

        ' OPM: volgende regels verwijderden de lay-outopmaak en zetten een spatie aan het begin van een nieuwe regel
        '' lay-outaanwijzingen die mensen zelf toegevoegd hebben
        'verv.Vervangen("<<", "<")
        'verv.Vervangen(">>", ">")
        'verv.Vervangen("<", " <")
        'verv.Vervangen("  <", " <")
        'verv.Vervangen(">", "> ")
        'verv.Vervangen(">  ", "> ")
    End Sub

    ''' <summary>
    ''' Voegt spaties toe na leestekens, volgens de afspraken met de lay-outers van Chirojeugd-Vlaanderen vzw
    ''' </summary>
    ''' <remarks>
    ''' "Why you should never, ever use two spaces after a period"
    ''' http://www.slate.com/articles/technology/technology/2011/01/space_invaders.html 
    ''' </remarks>
    Public Sub ChiroSpatiëringUitvoeren()
        verv = New Vervanging
        verv.Vervangen("  ", " ")
        verv.Vervangen("  ", " ")
        verv.Vervangen(". ", ".  ")
        verv.Vervangen("? ", "?  ")
        verv.Vervangen("! ", "!  ")

        verv.LeestekenFoutenVervangen()
    End Sub

    ''' <summary>
    ''' Markeert het bestand als 'klaar voor taalcorrectie'
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Afsluiten()
        doc = Globals.ThisAddIn.Application.ActiveDocument
        CommentToevoegen(EindredactieAfgerondString)
        doc.Save()

        If doc.Comments.Count > 0 Then
            ' Er zijn nog opmerkingen, dus kan de eindredactie nog niet afgerond zijn.
            ' Het bestand wordt opgeslagen maar nog niet afgesloten.
            If MessageBox.Show(FinaliserenMisluktString, FoutString, MessageBoxButtons.YesNo, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1) = DialogResult.Yes Then
                doc.Close()
            End If
        Else
            Dim bestandsnaam As String
            Dim nieuweBestandsnaam As String
            Dim pad As String

            ' Bestandsnaamconventies voor nagelezen bestanden toepassen: opslaan als doc ipv docx,
            ' en '!!!' voor de bestandsnaam zetten
            bestandsnaam = doc.Name
            pad = doc.Path

            If InStr(bestandsnaam, "!!!") = 1 Then
                nieuweBestandsnaam = bestandsnaam
            Else
                nieuweBestandsnaam = "!!! " & bestandsnaam
            End If
            nieuweBestandsnaam = nieuweBestandsnaam.Replace("  ", " ").Replace(".docx", ".doc")

            doc.SaveAs(Path.Combine(pad, nieuweBestandsnaam), WdSaveFormat.wdFormatDocument97)
            doc.Close()

            If bestandsnaam <> nieuweBestandsnaam Then
                Try
                    File.Delete(Path.Combine(pad, bestandsnaam))
                Catch ex As Exception
                    Throw New ApplicationException(VerwijderenMisluktString)
                End Try
            End If
        End If
    End Sub

    ''' <summary>
    ''' Zoekt clichés en twijfelachtige passages, en voegt daar een opmerking in met aanwijzingen of tips
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub RedactiefeedbackGeven()
        ' TODO (#157): clichés inlezen uit xml-bestand
        WoordZoekenEnOpmerkingToevoegen("dat ietsje meer", ClichéWaarschuwingString, False, False)
        WoordZoekenEnOpmerkingToevoegen("dat tikkeltje extra", ClichéWaarschuwingString, False, False)
        WoordZoekenEnOpmerkingToevoegen("dat tikkeltje meer", ClichéWaarschuwingString, False, False)
        WoordZoekenEnOpmerkingToevoegen("net ietsje meer", ClichéWaarschuwingString, False, False)
        WoordZoekenEnOpmerkingToevoegen("Maar hoe begin je daar nu aan?", ClichéWaarschuwingString, False, True)
        WoordZoekenEnOpmerkingToevoegen("Hoog tijd om ", ClichéWaarschuwingString, False, True)
        WoordZoekenEnOpmerkingToevoegen("Aan jou om ", ClichéWaarschuwingString, False, True)
        WoordZoekenEnOpmerkingToevoegen("tips en tricks", ClichéWaarschuwingString, False, False)
        WoordZoekenEnOpmerkingToevoegen("Tips en tricks", ClichéWaarschuwingString, False, False)
        WoordZoekenEnOpmerkingToevoegen("veel leesplezier", ClichéWaarschuwingString, False, False)
        WoordZoekenEnOpmerkingToevoegen("veel leesgenot", ClichéWaarschuwingString, False, False)
        WoordZoekenEnOpmerkingToevoegen("Of wat dacht je van", ClichéWaarschuwingString, False, True)
        WoordZoekenEnOpmerkingToevoegen("Of waarom niet eens", ClichéWaarschuwingString, False, True)

        WoordZoekenEnOpmerkingToevoegen("bekomt", BekomenWaarschuwingString, False, True)
        WoordZoekenEnOpmerkingToevoegen("bekomen", BekomenWaarschuwingString, False, True)

        WoordZoekenEnOpmerkingToevoegen("wat betreft", WatBetreftUitlegString, False, False)

        WoordZoekenEnOpmerkingToevoegen("als Chiro", AlsChiroUitlegString, True, False)

        WoordZoekenEnOpmerkingToevoegen("!!!", PuberleestekensUitlegString, False, False)
        WoordZoekenEnOpmerkingToevoegen("???", PuberleestekensUitlegString, False, False)

        ' TODO (#157): de opzoektermen voor url-verkorting in een apart bestand steken
        WoordZoekenEnOpmerkingToevoegen("www.", UrlVerkortingUitlegString, False, False)
        WoordZoekenEnOpmerkingToevoegen("utm_source=", UrlVerkortingUitlegString, False, False)
        WoordZoekenEnOpmerkingToevoegen("utm_medium=", UrlVerkortingUitlegString, False, False)
        WoordZoekenEnOpmerkingToevoegen("utm_term=", UrlVerkortingUitlegString, False, False)
        WoordZoekenEnOpmerkingToevoegen("utm_content=", UrlVerkortingUitlegString, False, False)
        WoordZoekenEnOpmerkingToevoegen("utm_campaign=", UrlVerkortingUitlegString, False, False)
        WoordZoekenEnOpmerkingToevoegen("fb_source=", UrlVerkortingUitlegString, False, False)
        WoordZoekenEnOpmerkingToevoegen("ref=bookmarks", UrlVerkortingUitlegString, False, False)
        WoordZoekenEnOpmerkingToevoegen("fb_action_ids=", UrlVerkortingUitlegString, False, False)
        WoordZoekenEnOpmerkingToevoegen("fb_action_types=", UrlVerkortingUitlegString, False, False)

        WoordZoekenEnOpmerkingToevoegen("onderzoek wijst ", BronvermeldingWaarschuwingString, False, False)
        WoordZoekenEnOpmerkingToevoegen("onderzoek toont ", BronvermeldingWaarschuwingString, False, False)

        WoordZoekenEnOpmerkingToevoegen("ook", StopwoordWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("eigenlijk", StopwoordWaarschuwingString, False, False)
        WoordZoekenEnOpmerkingToevoegen("in feite", StopwoordWaarschuwingString, True, False)

        WoordZoekenEnOpmerkingToevoegen("Doel is", JournalistiekDoelIsWaarschuwingString, True, True)
        WoordZoekenEnOpmerkingToevoegen("Bedoeling is", JournalistiekDoelIsWaarschuwingString, True, True)
        WoordZoekenEnOpmerkingToevoegen("Feit is", JournalistiekFeitIsWaarschuwingString, True, True)

        WoordZoekenEnOpmerkingToevoegen("worden", PassivitisWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("geworden", PassivitisWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("werden", PassivitisWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("wordt", PassivitisWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("word", PassivitisWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("werd", PassivitisWaarschuwingString, True, False)

        ' Top 10 van de vaagtaal in de personeelspraat (http://vaagtaal.nl/personeelspraat/top-10-meest-misbruikt/)
        WoordZoekenEnOpmerkingToevoegen("actief", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("actieve", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("resultaatgericht", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("flexibel", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("innovatief", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("innovatieve", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("dynamisch", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("complex", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("complexe", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("proactief", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("gedreven", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("klantgericht", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("competentie", VaagtaalWaarschuwingString, True, False)
        WoordZoekenEnOpmerkingToevoegen("competenties", VaagtaalWaarschuwingString, True, False)

        WoordZoekenEnOpmerkingToevoegen("^p^p^p^p^p", "Probeer je zo een hoofdstuk op een volgende bladzijde te laten beginnen? Gebruik Ctrl-Enter, dan schuift dat niet meer op als je iets aan de tekst verandert", False, False)
    End Sub

    Public Function WoordenTellen() As Data.DataTable
        Dim woordentabel As New Data.DataTable
        Dim woord As String
        Dim rijen() As DataRow
        Dim rij As DataRow

        With woordentabel.Columns
            .Add("Woord", GetType(String))
            .Add("Aantal", GetType(Int32))
        End With

        doc = Globals.ThisAddIn.Application.ActiveDocument

        For i As Int32 = 1 To doc.Words.Count
            woord = doc.Words(i).Text.Trim().ToLower()

            ' Leestekens en spaties worden blijkbaar als Word-range gezien, maar die willen we niet tellen.
            ' Ook cijfers moeten er niet bij.
            ' OPM: chiro.be bestaat uit drie 'woorden'!
            If Regex.IsMatch(woord, "^[A-Za-z]*$") Then
                rijen = woordentabel.Select(String.Format("Woord = '{0}'", Replace(woord, "'", "''")))
                If rijen.Length = 0 Then
                    rij = woordentabel.NewRow()
                    rij("Woord") = woord
                    rij("Aantal") = 1
                    woordentabel.Rows.Add(rij)
                Else
                    rijen(0)("Aantal") = CInt(rijen(0)("Aantal")) + 1
                End If
            End If

            'If woord <> "" AndAlso woord <> "." AndAlso woord <> "?" AndAlso woord <> "!" AndAlso woord <> "," AndAlso woord <> ";" Then

            'End If
        Next

        Return woordentabel
    End Function

#End Region

#Region " private helper methods "

    ''' <summary>
    ''' Leest het xml-bestand met verbeteringsinstellingen in, en voert per 'rubriek' een aantal vervangen uit
    ''' zonder toestemming te vragen aan de gebruiker
    ''' </summary>
    ''' <remarks></remarks>
    Friend Sub AutomatischVervangen(Optional isAanvullendeVervanging As Boolean = False)
        ' Variabelen om instellingenbestand te kunnen lezen
        Dim childnodes As XmlNodeList
        Dim child As Xml.XmlNode
        Dim xpath As String

        Dim pad As String
        Dim bestandsnaam As String

        ' Eerst leestekenvervangingen die niet via xml-input kunnen gebeuren
        verv = New Vervanging
        verv.LeestekenFoutenVervangen()

        ' Gebruik xml-bestand voor verdere vervangingen
        pad = My.Settings.Verbeteringsinstellingenpad

        If isAanvullendeVervanging Then
            bestandsnaam = BESTANDSNAAM_NIEUWE_VERVANGINGEN
        Else
            bestandsnaam = BESTANDSNAAM_VERVANGINGEN
        End If

        Try
            If File.Exists(Path.Combine(pad, bestandsnaam)) Then
                xdoc.Load(Path.Combine(pad, bestandsnaam))
            Else
                MessageBox.Show(InstellingenAutomatischVervangenOntbrekenString, FoutString, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1)
                Exit Sub
            End If
        Catch ex As FileNotFoundException
            MessageBox.Show(InstellingenAutomatischVervangenOntbrekenString, FoutString, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1)
            Exit Sub
        End Try

        ' Zoek de nodes voor vervangingen die zonder meer mogen gebeuren
        xpath = String.Format("Vervangingen/ZonderMeer/Vervanging")
        childnodes = xdoc.SelectNodes(xpath)

        For Each child In childnodes
            verv.Vervangen(child.FirstChild.InnerText, child.ChildNodes(1).InnerText)
        Next

        ' Zoek de nodes voor hoofdlettergevoelige vervangingen die zonder meer mogen gebeuren
        xpath = String.Format("Vervangingen/ZonderMeer/HoofdletterVervanging")
        childnodes = xdoc.SelectNodes(xpath)

        For Each child In childnodes
            verv.Vervangen(child.FirstChild.InnerText, child.ChildNodes(1).InnerText, True)
        Next

        ' Zoek de nodes voor vervangingen waar de woordgrens meespeelt
        xpath = String.Format("Vervangingen/ZonderMeer/WoordgrensVervanging")
        childnodes = xdoc.SelectNodes(xpath)

        For Each child In childnodes
            verv.MetWoordgrensVervangen(child.FirstChild.InnerXml, _
                                        child.ChildNodes(1).InnerXml, _
                                        CBool(child.ChildNodes(2).InnerXml), _
                                        CBool(child.ChildNodes(3).InnerXml))
        Next

        ' Zoek de nodes voor vervangingen met keuzeopties
        xpath = String.Format("Vervangingen/MetOpties/Vervanging")
        childnodes = xdoc.SelectNodes(xpath)

        For Each child In childnodes
            Dim uitleg As String
            ' Uitleg staat bij vervanging met opties in de 5e childnode
            If child.ChildNodes.Count >= 5 Then
                uitleg = child.ChildNodes(4).InnerXml
            Else
                uitleg = String.Empty
            End If

            VervangingMetOptiesUitvoeren(child.FirstChild.InnerXml, child.ChildNodes(1).InnerXml, child.ChildNodes(2).InnerXml, _
                     child.ChildNodes(3).InnerXml, uitleg)
        Next

        ' Zoek de nodes voor vervangingen met keuzeopties waar de woordgrens meespeelt
        xpath = String.Format("Vervangingen/MetOpties/WoordgrensVervanging")
        childnodes = xdoc.SelectNodes(xpath)

        For Each child In childnodes
            Dim uitleg As String
            ' Uitleg staat bij woordgrensvervanging met opties in de 7e childnode
            If child.ChildNodes.Count >= 7 Then
                uitleg = child.ChildNodes(6).InnerXml
            Else
                uitleg = String.Empty
            End If

            VervangingMetOptiesUitvoeren(child.FirstChild.InnerXml, child.ChildNodes(1).InnerXml, child.ChildNodes(2).InnerXml, _
                     child.ChildNodes(3).InnerXml, uitleg, CBool(child.ChildNodes(4).InnerXml), CBool(child.ChildNodes(5).InnerXml))
        Next
    End Sub

    ''' <summary>
    ''' Zoekt het triggerwoord, kijkt of de zin een van de woorden uit een lijstje bevat,
    ''' en als die combinatie voorkomt, voegen we een opmerking in.
    ''' </summary>
    ''' <remarks>
    ''' Dit is voor de gevallen waarin er woorden tussen de combinatie kunnen staan.
    ''' Bij de automatische vervanging moeten de woorden naast elkaar staan, hier hoeft dat niet
    ''' - maar dat betekent ook dat automatisch vervangen tot fouten kan leiden,
    ''' want het is niet omdat twee woorden in één zin voorkomen dat ze ook bij elkaar horen.
    ''' </remarks>
    Friend Sub VervangingsfeedbackToevoegen()
        Dim arl As New ArrayList

        With arl
            .Add("trekken")
            .Add("trek")
            .Add("trekt")
            .Add("trok")
            .Add("getrokken")
        End With

        ' De volgende regel vindt zowel foto als foto's, maar niet fotograaf
        WoordcombinatieZoekenEnOpmerkingToevoegen("foto", arl, FotoTrekkenUitlegString, FotoTrekkenUrlString)

        arl = New ArrayList
        With arl
            .Add("daarnaast")
            .Add("verder")
            .Add("bovendien")
            .Add("net als")
        End With

        WoordcombinatieZoekenEnOpmerkingToevoegen("ook", arl, DubbeleOokUitlegString)

        arl = New ArrayList()
        With arl
            .Add("kan")
            .Add("kun")
            .Add("kunt")
            .Add("kunnen")
        End With

        WoordcombinatieZoekenEnOpmerkingToevoegen("misschien", arl, TwijfelstijlUitlegString)
        WoordcombinatieZoekenEnOpmerkingToevoegen("eventueel", arl, TwijfelstijlUitlegString)
        WoordcombinatieZoekenEnOpmerkingToevoegen("vinden", arl, BekwaamheidstwijfelUitlegString)

        arl = New ArrayList()
        With arl
            .Add("hou")
            .Add("Hou")
        End With

        WoordcombinatieZoekenEnOpmerkingToevoegen("in de gaten", arl, InDeGatenUitlegString)
    End Sub

    ''' <summary>
    ''' Zoekt een bepaald woord of een bepaalde woordgroep, en stelt een aantal alternatieven voor
    ''' waar de gebruiker een keuze uit kan maken. Eventueel krijgt de gebruiker ook wat uitleg over
    ''' waarom die vervanging voorgesteld wordt.
    ''' </summary>
    ''' <param name="ZoektermParam">
    ''' Het woord dat of de woordgroep die in bepaalde (of alle) gevallen best vervangen wordt door een alternatief
    ''' </param>
    ''' <param name="OptieParam1">Een eerste alternatief</param>
    ''' <param name="OptieParam2">Een tweede alternatief</param>
    ''' <param name="OptieParam3">Een derde alternatief</param>
    ''' <param name="UitlegParam">Eventueel wat uitleg over waarom de vervanging voorgesteld wordt</param>
    ''' <param name="MetBegingrensParam">
    ''' <c>True</c> als het begin van <paramref name="ZoektermParam" /> moet samenvallen met een woordgrens,
    ''' <c>false</c> of <c>nothing</c> als dat niet noodzakelijk is</param>
    ''' <param name="MetEindgrensParam">
    ''' ''' <c>True</c> als het einde van <paramref name="ZoektermParam" /> moet samenvallen met een woordgrens,
    ''' <c>false</c> of <c>nothing</c> als dat niet noodzakelijk is</param>
    Private Sub VervangingMetOptiesUitvoeren(ByVal ZoektermParam As String, ByVal OptieParam1 As String, _
                                          ByVal OptieParam2 As String, ByVal OptieParam3 As String, Optional UitlegParam As String = "", _
                                          Optional ByVal MetBegingrensParam As Boolean = False, _
                                          Optional ByVal MetEindgrensParam As Boolean = False)

        vervangForm = New VervangMetOptiesVenster(ZoektermParam, OptieParam1, OptieParam2, OptieParam3, UitlegParam, MetBegingrensParam, MetEindgrensParam)
        vervangForm.VervangingenUitvoeren()
        vervangForm.Close()
    End Sub

    ''' <summary>
    ''' Zet de weergave zo groot mogelijk om goed leesbaar te zijn, 
    ''' en zo dat opmerkingen en dergelijke ook zichtbaar zijn.
    ''' </summary>
    Private Sub WeergaveRegelen()
        ' Actief venster identificeren
        Dim venster As Window
        venster = Globals.ThisAddIn.Application.ActiveWindow

        ' Zet de weergave zo groot mogelijk om goed leesbaar te zijn, 
        ' en zo dat opmerkingen en dergelijke ook zichtbaar zijn.
        venster.View.Type = WdViewType.wdPrintView

        ' Als het beeld smaller geworden is door een opmerking toe te voegen, helpt het niet als je alleen
        ' de regel met BestFit uitvoert. Vandaar de omweg via TextFit.
        venster.ActivePane.View.Zoom.PageFit = WdPageFit.wdPageFitTextFit
        venster.ActivePane.View.Zoom.PageFit = WdPageFit.wdPageFitBestFit
    End Sub

    ''' <summary>
    ''' Zoekt de opgegeven tekst in het document en voegt op elke vindplaats een opmerking toe,
    ''' waarin de gebruiker kan lezen dat het om een clichéformulering gaat.
    ''' </summary>
    ''' <param name="ZoektermParam">
    ''' Het woord dat of de woordgroep die we willen zoeken
    ''' </param>
    ''' <param name="OpmerkingParam">De feedback die we de gebruiker willen geven</param>
    Private Sub WoordZoekenEnOpmerkingToevoegen(ByVal ZoektermParam As String, ByVal OpmerkingParam As String, ByVal MetWoordgrens As Boolean, ByVal MetHoofdletters As Boolean, Optional ByVal UitlegUrlParam As String = "")
        Dim conv As Conversie
        Dim webadres As Uri

        verv = New Vervanging
        selectie = Globals.ThisAddIn.Application.Selection

        verv.OpmaakVervangingResetten()

        With selectie.Find
            .Text = ZoektermParam
            .MatchWholeWord = MetWoordgrens
            .MatchCase = MetHoofdletters
            .Execute()
        End With

        Do While selectie.Find.Found = True
            Try
                conv = New Conversie()

                If Uri.TryCreate(UitlegUrlParam, UriKind.Absolute, webadres) Then
                    conv.OpmerkingInvoegen(OpmerkingParam, webadres)
                Else
                    webadres = Nothing
                    conv.OpmerkingInvoegen(OpmerkingParam)
                End If

                selectie.MoveRight(Unit:=WdUnits.wdCharacter, Count:=2)
                selectie.Find.Execute()
            Catch ex As Exception
                MessageBox.Show(ex.Message, FoutString, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1)
                Exit Do
            End Try
        Loop

        ' Opmerkingenpanel sluiten
        If Globals.ThisAddIn.Application.ActiveWindow.Panes.Count > 1 Then
            Globals.ThisAddIn.Application.ActiveWindow.ActivePane.Close()
        End If

        verv.OpmaakVervangingResetten()
    End Sub

    Private Sub WoordcombinatieZoekenEnOpmerkingToevoegen(TriggerwoordParam As String, CombinatiewoordenParam As ArrayList, OpmerkingParam As String, Optional UitlegUrlParam As String = "")
        Dim conv As Conversie
        Dim webadres As Uri

        verv = New Vervanging
        selectie = Globals.ThisAddIn.Application.Selection

        verv.OpmaakVervangingResetten()

        With selectie.Find
            .Text = TriggerwoordParam
            .MatchWholeWord = True
            .Execute()
        End With

        Do While selectie.Find.Found = True
            ' De hele zin selecteren
            With selectie
                .Collapse()
                .Expand(Unit:=WdUnits.wdSentence)
            End With

            ' Nagaan of er een woord in voorkomt dat in de arraylist meegegeven werd
            For i As Int16 = 1 To selectie.Words.Count
                ' Soms bestaat een 'zin' maar uit één woord. In zo'n geval werkt de regel
                ' hierboven niet.
                If i >= selectie.Words.Count Then
                    Exit For
                End If

                Dim gewoonwoord As String
                gewoonwoord = selectie.Words(i).Text.ToLower().Trim()

                If CombinatiewoordenParam.Contains(gewoonwoord) Then
                    Try
                        conv = New Conversie()

                        If Uri.TryCreate(UitlegUrlParam, UriKind.Absolute, webadres) Then
                            conv.OpmerkingInvoegen(OpmerkingParam, webadres)
                        Else
                            webadres = Nothing
                            conv.OpmerkingInvoegen(OpmerkingParam)
                        End If
                    Catch ex As Exception
                        MessageBox.Show(ex.Message, FoutString, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1)
                        Exit Do
                    End Try
                End If
            Next

            selectie.MoveRight(Unit:=WdUnits.wdWord, Count:=1)
            selectie.Find.Execute()
        Loop

        ' Opmerkingenpanel sluiten
        If Globals.ThisAddIn.Application.ActiveWindow.Panes.Count > 1 Then
            Globals.ThisAddIn.Application.ActiveWindow.ActivePane.Close()
        End If

        verv.OpmaakVervangingResetten()
    End Sub

#End Region

End Module